using System.Text;
using System;
using System.Data;
using System.Data.SqlClient;
using Csla;
using Csla.Data;
using Csla.Validation;
using BA.DAL;
using BA;


namespace BlazeApps.Library.Forum
{ 
	[Serializable()] 
	public class Post : Csla.BusinessBase<Post>
	{
        private BlazeApps.Library.ConfigSettings Config = new BlazeApps.Library.ConfigSettings();
        private BA.DAL.DBUtility DAL = new BA.DAL.DBUtility();
        private Procedures Procs = new Procedures();

		#region Business Properties and Methods

		//declare members
		private Guid _postID = Guid.NewGuid();
		private Guid _topicID = Guid.Empty;
		private Guid _repliedTo = Guid.Empty;
		private Guid _userID = Guid.Empty;
        private SmartDate _created = new SmartDate(DateTime.Now);
		private string _postBody = string.Empty;
        private SmartDate _edited = new SmartDate(DateTime.Now);
        private Boolean _IsApproved = false;

		[System.ComponentModel.DataObjectField(true, false)]
		public Guid PostID
		{
			get
			{
				CanReadProperty("PostID", true);
				return _postID;
			}
		}

		public Guid TopicID
		{
			get
			{
				CanReadProperty("TopicID", true);
				return _topicID;
			}
			set
			{
				CanWriteProperty("TopicID", true);
				if (!_topicID.Equals(value))
				{
					_topicID = value;
					PropertyHasChanged("TopicID");
				}
			}
		}

		public Guid RepliedTo
		{
			get
			{
				CanReadProperty("RepliedTo", true);
				return _repliedTo;
			}
			set
			{
				CanWriteProperty("RepliedTo", true);
				if (!_repliedTo.Equals(value))
				{
					_repliedTo = value;
					PropertyHasChanged("RepliedTo");
				}
			}
		}

		public Guid UserID
		{
			get
			{
				CanReadProperty("UserID", true);
				return _userID;
			}
			set
			{
				CanWriteProperty("UserID", true);
				if (!_userID.Equals(value))
				{
					_userID = value;
					PropertyHasChanged("UserID");
				}
			}
		}

		public DateTime Created
		{
			get
			{
				CanReadProperty("Created", true);
				return _created.Date;
			}
		}

		public string CreatedString
		{
			get
			{
				CanReadProperty("CreatedString", true);
				return _created.Text;
			}
			set
			{
				CanWriteProperty("CreatedString", true);
				if (value == null) value = string.Empty;
				if (!_created.Equals(value))
				{
					_created.Text = value;
					PropertyHasChanged("CreatedString");
				}
			}
		}

		public string PostBody
		{
			get
			{
                CanReadProperty("PostBody", true);
                return _postBody;
			}
			set
			{
				CanWriteProperty("PostBody", true);
				if (value == null) value = string.Empty;
            if (!_postBody.Equals(value))
				{
                    _postBody = value;
                    PropertyHasChanged("PostBody");
				}
			}
		}

		public DateTime Edited
		{
			get
			{
				CanReadProperty("Edited", true);
				return _edited.Date;
			}
		}

        public Boolean IsApproved
        {
            get
            {
                return _IsApproved;
            }
            set
            {
                CanWriteProperty("IsApproved", true);
                if(!_IsApproved.Equals(value))
                {
                    _IsApproved = value;
                    PropertyHasChanged("IsApproved");
                }
            }
        }

		public string EditedString
		{
			get
			{
				CanReadProperty("EditedString", true);
				return _edited.Text;
			}
			set
			{
				CanWriteProperty("EditedString", true);
				if (value == null) value = string.Empty;
				if (!_edited.Equals(value))
				{
					_edited.Text = value;
					PropertyHasChanged("EditedString");
				}
			}
		}
 
		protected override object GetIdValue()
		{
			return _postID;
		}

		#endregion //Business Properties and Methods

		#region Validation Rules
		private void AddCustomRules()
		{
			//add custom/non-generated rules here...
		}

		private void AddCommonRules()
		{
			//
			// Post
			//
            ValidationRules.AddRule(CommonRules.StringRequired, "PostBody");
		}

		protected override void AddBusinessRules()
		{
			AddCommonRules();
			AddCustomRules();
		}
		#endregion //Validation Rules

		#region Authorization Rules
		protected override void AddAuthorizationRules()
		{
			//TODO: Define authorization rules in Post
			//AuthorizationRules.AllowRead("PostID", "PostReadGroup");
			//AuthorizationRules.AllowRead("TopicID", "PostReadGroup");
			//AuthorizationRules.AllowRead("RepliedTo", "PostReadGroup");
			//AuthorizationRules.AllowRead("UserID", "PostReadGroup");
			//AuthorizationRules.AllowRead("Created", "PostReadGroup");
			//AuthorizationRules.AllowRead("CreatedString", "PostReadGroup");
			//AuthorizationRules.AllowRead("Post", "PostReadGroup");
			//AuthorizationRules.AllowRead("Edited", "PostReadGroup");
			//AuthorizationRules.AllowRead("EditedString", "PostReadGroup");

			//AuthorizationRules.AllowWrite("TopicID", "PostWriteGroup");
			//AuthorizationRules.AllowWrite("RepliedTo", "PostWriteGroup");
			//AuthorizationRules.AllowWrite("UserID", "PostWriteGroup");
			//AuthorizationRules.AllowWrite("CreatedString", "PostWriteGroup");
			//AuthorizationRules.AllowWrite("Post", "PostWriteGroup");
			//AuthorizationRules.AllowWrite("EditedString", "PostWriteGroup");
		}


		public static bool CanGetObject()
		{
			//TODO: Define CanGetObject permission in Post
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("PostViewGroup"))
			//	return true;
			//return false;
		}

		public static bool CanAddObject()
		{
			//TODO: Define CanAddObject permission in Post
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("PostAddGroup"))
			//	return true;
			//return false;
		}

		public static bool CanEditObject()
		{
			//TODO: Define CanEditObject permission in Post
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("PostEditGroup"))
			//	return true;
			//return false;
		}

		public static bool CanDeleteObject()
		{
			//TODO: Define CanDeleteObject permission in Post
			return true;
			//if (Csla.ApplicationContext.User.IsInRole("PostDeleteGroup"))
			//	return true;
			//return false;
		}
		#endregion //Authorization Rules

		#region Factory Methods
		private Post()
		{ /* require use of factory method */ }

		public static Post NewPost()
		{
			if (!CanAddObject())
				throw new System.Security.SecurityException("User not authorized to add a Post");
			return DataPortal.Create<Post>();
		}

		public static Post GetPost(Guid postID)
		{
			if (!CanGetObject())
				throw new System.Security.SecurityException("User not authorized to view a Post");
			return DataPortal.Fetch<Post>(new Criteria(postID));
		}

		public static void DeletePost(Guid postID)
		{
			if (!CanDeleteObject())
				throw new System.Security.SecurityException("User not authorized to remove a Post");
			DataPortal.Delete(new Criteria(postID));
		}

		public override Post Save()
		{
			if (IsDeleted && !CanDeleteObject())
				throw new System.Security.SecurityException("User not authorized to remove a Post");
			else if (IsNew && !CanAddObject())
				throw new System.Security.SecurityException("User not authorized to add a Post");
			else if (!CanEditObject())
				throw new System.Security.SecurityException("User not authorized to update a Post");

			return base.Save();
		}

		#endregion //Factory Methods

		#region Data Access

		#region Criteria

		[Serializable()]
		private class Criteria
		{
			public Guid PostID;

			public Criteria(Guid postID)
			{
				this.PostID = postID;
			}
		}

		#endregion //Criteria

		#region Data Access - Create
		[RunLocal]
		protected override void DataPortal_Create()
		{
			ValidationRules.CheckRules();
		}

		#endregion //Data Access - Create

		#region Data Access - Fetch
        private void DataPortal_Fetch(Criteria criteria)
        {
            ExecuteFetch(criteria);
        }

        private void ExecuteFetch(Criteria criteria)
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            DAL.AddParameter("@PostID", criteria.PostID);

            using(SafeDataReader dr = new SafeDataReader(DAL.ExecuteReader(Procs.GetPostByPostID.ToString().Trim(), CommandType.Text, ConnectionState.Open)))
            {
                FetchObject(dr);
                ValidationRules.CheckRules();

                //load child object(s)
                FetchChildren(dr);
            }
        }

		private void FetchObject(SafeDataReader dr)
		{
			dr.Read();
			_postID = dr.GetGuid("PostID");
			_topicID = dr.GetGuid("TopicID");
			_repliedTo = dr.GetGuid("RepliedTo");
			_userID = dr.GetGuid("UserID");
			_created = dr.GetSmartDate("Created", _created.EmptyIsMin);
			_postBody = dr.GetString("Post");
			_edited = dr.GetSmartDate("Edited", _edited.EmptyIsMin);
            _IsApproved = dr.GetBoolean("IsApproved");
		}

		private void FetchChildren(SafeDataReader dr)
		{
		}
		#endregion //Data Access - Fetch

		#region Data Access - Insert
        protected override void DataPortal_Insert()
        {
            ExecuteInsert();
        }

        private void ExecuteInsert()
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            AddInsertParameters(ref DAL);

            DAL.ExecuteNonQuery(Procs.InsertPost.ToString().Trim(), CommandType.Text, ConnectionState.Open);

            if(_IsApproved)
            {
                UpdateTopicLastUser();
                UpdateForumLastUser();
                UpdateCategoryLastUser();
                UpdateBoardLastUser();
            }
        }

        private void AddInsertParameters(ref BA.DAL.DBUtility DAL)
		{
			DAL.AddParameter("@PostID", _postID);
            DAL.AddParameter("@Post", _postBody);
			DAL.AddParameter("@TopicID", _topicID);
            DAL.AddParameter("@UserID", _userID);

            if (_repliedTo != Guid.Empty)
                DAL.AddParameter("@RepliedTo", _repliedTo);
            else
                DAL.AddParameter("@RepliedTo", DBNull.Value);

            DAL.AddParameter("@Created", _created.DBValue);
            DAL.AddParameter("@Edited", _edited.DBValue);
            DAL.AddParameter("@IsApproved", _IsApproved);
		}

        private void UpdateTopicLastUser()
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            DAL.AddParameter("@TopicID", _topicID);
            DAL.AddParameter("@LastUserID", _userID);
            DAL.AddParameter("@LastPostDate", _created.DBValue);

            DAL.ExecuteNonQuery(Procs.UpdateTopicLastUser.ToString().Trim(), CommandType.Text, ConnectionState.Open);
        }

        private void UpdateForumLastUser()
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            DAL.AddParameter("@TopicID", _topicID);
            DAL.AddParameter("@LastUserID", _userID);
            DAL.AddParameter("@LastPostDate", _created.DBValue);

            DAL.ExecuteNonQuery(Procs.UpdateForumLastUser.ToString().Trim(), CommandType.Text, ConnectionState.Open);
        }

        private void UpdateCategoryLastUser()
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            DAL.AddParameter("@TopicID", _topicID);
            DAL.AddParameter("@LastUserID", _userID);
            DAL.AddParameter("@LastPostDate", _created.DBValue);

            DAL.ExecuteNonQuery(Procs.UpdateCategoryLastUser.ToString().Trim(), CommandType.Text, ConnectionState.Open);
        }

        private void UpdateBoardLastUser()
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            DAL.AddParameter("@TopicID", _topicID);
            DAL.AddParameter("@LastUserID", _userID);
            DAL.AddParameter("@LastPostDate", _created.DBValue);

            DAL.ExecuteNonQuery(Procs.UpdateBoardLastUser.ToString().Trim(), CommandType.Text, ConnectionState.Open);
        }

		#endregion //Data Access - Insert

		#region Data Access - Update
        protected override void DataPortal_Update()
        {
            if (base.IsDirty)
            {
                ExecuteUpdate();
            }
        }

        private void ExecuteUpdate()
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            AddUpdateParameters(ref DAL);

            DAL.ExecuteNonQuery(Procs.UpdatePost.ToString().Trim(), CommandType.Text, ConnectionState.Open);
        }

        private void AddUpdateParameters(ref BA.DAL.DBUtility DAL)
		{
			DAL.AddParameter("@PostID", _postID);
            DAL.AddParameter("@Post", _postBody);
			DAL.AddParameter("@TopicID", _topicID);
            DAL.AddParameter("@UserID", _userID);

            if (_repliedTo != Guid.Empty)
                DAL.AddParameter("@RepliedTo", _repliedTo);
            else
                DAL.AddParameter("@RepliedTo", DBNull.Value);

            DAL.AddParameter("@Created", _created.DBValue);
            DAL.AddParameter("@Edited", _edited.DBValue);
            DAL.AddParameter("@IsApproved", _IsApproved);
		}

		private void UpdateChildren(SqlConnection cn)
		{
		}
		#endregion //Data Access - Update

		#region Data Access - Delete
        protected override void DataPortal_DeleteSelf()
        {
            DataPortal_Delete(new Criteria(_postID));
        }

        private void DataPortal_Delete(Criteria criteria)
        {
            ExecuteDelete(criteria);
        }

        private void ExecuteDelete(Criteria criteria)
        {
            DAL.CreateDBObjects(Config.ConnectionString, Config.Provider);

            AddDeleteParameters(ref DAL, criteria);

            DAL.ExecuteNonQuery(Procs.DeletePost.ToString().Trim(), CommandType.Text, ConnectionState.Open);
            Procs.PurgeItemsByItemID(criteria.PostID);
        }

        private void AddDeleteParameters(ref BA.DAL.DBUtility DAL, Criteria criteria)
        {
            DAL.AddParameter("@PostID", criteria.PostID);
        }
		#endregion //Data Access - Delete
		#endregion //Data Access
	}
}
